using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace BardsTaleMapViewer {
  public class Beastiary {
    public Game _game;

    public List<string> _monsterTypesName;
    public List<int> _monsterTypesPlus1AttackEffectAndPower;
    public List<int> _monsterTypesPlus1PictureIndex;
    public List<int []> _monsterTypesPlus1Actions;
    public List<int> _monsterTypesPlus1HitTypeIndex;
    public List<int> _monsterTypesPlus1Experience;
    public List<int> _monsterTypesPlus1HpMinAndArmorClassBonus;
    public List<int> _monsterTypesPlus1HpSizeAndNbSize;

    public List<MonsterType> _monsterTypes;
    public List<int> _sizes;
    public List<int> _difficultiesGoldPerKillMask;
    public List<int> _difficultiesMonsterTypePlus1Base;
    public List<int> _difficultiesMonsterTypeRandomMask;
    public List<int> _actionsSpellIndex;

    public List<string> _specials;

    public Beastiary (Game game) {
      _game = game;
      // Name
      _monsterTypesName = Game.ReadArrayString (0x3095C, 0x30B58, 127, false);
      //_monsterTypesName = new List<string> ();
      //int address = 0x3095C;
      //for (int i = 0; i < 127; i++) {
      //  int address2 = (int) Game._dumpAtari.ReadLong (ref address);
      //  string name = Game._dumpAtari.ReadString (address2);
      //  _monsterTypesName.Add (name);
      //}
      //if (address != 0x30B58)
      //  throw new Exception ();

      // Strength
      _monsterTypesPlus1AttackEffectAndPower = Game.ReadArrayInt (0x2E862, 0x2E8E2, 128);

      // Picture Index
      _monsterTypesPlus1PictureIndex = Game.ReadArrayInt (0x2EDD0, 0x2EE50, 128);

      // Actions
      _monsterTypesPlus1Actions = new List<int []> ();
      int address = 0x2E962;
      for (int i = 0; i < 128; i++) {
        int [] actions = new int [4];
        for (int j = 0; j < 4; j++) {
          int action = Game._dumpAtari.ReadByte (ref address);
          if ((action >= 40) && (action <= 78))
            throw new Exception ();
          actions [j] = action;
        }
        _monsterTypesPlus1Actions.Add (actions);
      }
      if (address != 0x2EB62)
        throw new Exception ();

      // Hit Type Index
      _monsterTypesPlus1HitTypeIndex = Game.ReadArrayInt (0x2EC04, 0x2EC84, 128);

      // Experience
      _monsterTypesPlus1Experience = Game.ReadArrayInt (0x2E8E2, 0x2E962, 128);

      // HpMinAndArmorClassBonus
      _monsterTypesPlus1HpMinAndArmorClassBonus = Game.ReadArrayInt (0x2E7E2, 0x2E862, 128);

      // NbSizeAndHpSize
      _monsterTypesPlus1HpSizeAndNbSize = Game.ReadArrayInt (0x2E762, 0x2E7E2, 128);

      // Specials
      _specials = Game.ReadArrayString (0x2EF92, 0x2EF9E, 3, true);
      //_specials = new List<string> ();
      //address = 0x2EF92;
      //for (int i = 0; i < 3; i++) {
      //  int address2 = (int) Game._dumpAtari.ReadLong (ref address);
      //  string name = Game._dumpAtari.ReadString (address2);
      //  _specials.Add (name.Trim ());
      //}
      //if (address != 0x2EF9E)
      //  throw new Exception ();

      // Sizes
      _sizes = Game.ReadArrayInt (0x2ECFE, 0x2ED06, 8);

      // DifficultiesGoldPerKillMask
      _difficultiesGoldPerKillMask = Game.ReadArrayInt (0x2EDB0, 0x2EDB8, 8);

      // DifficultiesMonsterTypeBase
      _difficultiesMonsterTypePlus1Base = Game.ReadArrayInt (0x2ED06, 0x2ED0E, 8);

      // DifficultiesMonsterTypeRandomMask
      _difficultiesMonsterTypeRandomMask = Game.ReadArrayInt (0x2ECF6, 0x2ECFE, 8);

      // ActionsSpellIndex
      _actionsSpellIndex = Game.ReadArrayInt (0x2EFBC, 0x2EFE4, 40);

      // MonsterTypes
      _monsterTypes = new List<MonsterType> ();
      for (int i = 0; i < 127; i++) {
        MonsterType monsterType = new MonsterType (i, this);
        _monsterTypes.Add (monsterType);
      }
    }

    public static string GetSingular (string name) {
      string [] split = name.Split ('^');
      if (split.Length == 1)
        return (split [0]);
      return (split [0] + split [1]);
    }

    public static string GetPlural (string name) {
      string [] split = name.Split ('^');
      if (split.Length == 1)
        return (split [0]);
      return (split [0] + split [2]);
    }

    public List<bool> GetDifficultiesPresent (int indexPlus1) {
      List<bool> difficultiesPresent = new List<bool> ();
      for (int i = 0; i < 8; i++) {
        int monsterTypePlus1Base = _difficultiesMonsterTypePlus1Base [i];
        int monsterTypeRandomMask = _difficultiesMonsterTypeRandomMask [i];
        int monsterTypePlus1Max = monsterTypePlus1Base + monsterTypeRandomMask;
        if ((indexPlus1 >= monsterTypePlus1Base) && (indexPlus1 <= monsterTypePlus1Max))
          difficultiesPresent.Add (true);
        else
          difficultiesPresent.Add (false);
      }
      return (difficultiesPresent);
    }

    public string GetDifficultiesString (int indexPlus1) {
      List<bool> difficultiesPresent = GetDifficultiesPresent (indexPlus1);
      StringBuilder difficultiesString = new StringBuilder ();
      for (int i = 0; i < 8; i++) {
        bool difficultyPresent = difficultiesPresent [i];
        if (difficultyPresent)
          difficultiesString.Append (i);
        else
          difficultiesString.Append ("-");
      }
      return (difficultiesString.ToString ());
    }

    public void Dump () {
      int nameLength = Game.Lengthest (_monsterTypesName);
      int attackEffectLength = Game.Lengthest (MonsterType._attackEffectsString);
      int hitTypeLength = Game.Lengthest (MonsterType._hitTypesString);

      StringBuilder sb = new StringBuilder ();
      sb.AppendFormat ("{0,3}", "#");
      sb.AppendFormat ("  {0,-8}", "AtDiff");
      sb.AppendFormat ("  {0,-" + nameLength + "}", "Name");
      sb.AppendFormat ("  {0,5}", "Power");
      sb.AppendFormat ("  {0,3}", "Pic");
      sb.AppendFormat ("  {0,-8}", "HP");
      sb.AppendFormat ("  {0,2}", "AC");
      sb.AppendFormat ("  {0,-6}", "Nb");
      sb.AppendFormat ("  {0,-14}", "Damage");
      sb.AppendFormat ("  {0,-" + hitTypeLength + "}", "HitType");
      sb.AppendFormat ("  {0,-" + attackEffectLength + "}", "AttackEffect");
      sb.AppendFormat ("  {0,-4}", "XP");
      sb.AppendFormat ("  {0,3}", "A1");
      sb.AppendFormat ("  {0,3}", "A2");
      sb.AppendFormat ("  {0,3}", "A3");
      sb.AppendFormat ("  {0,3}", "A4");
      Console.WriteLine (sb.ToString ());

      foreach (MonsterType monsterType in _monsterTypes)
        monsterType.Dump ();
    }

    public StringBuilder DumpHtml () {
      int nameLength = Game.Lengthest (_monsterTypesName);
      int attackEffectLength = Game.Lengthest (MonsterType._attackEffectsString);
      int hitTypeLength = Game.Lengthest (MonsterType._hitTypesString);

      StringBuilder sb = new StringBuilder ();
      sb.AppendLineFormat ("<table>");
      sb.AppendFormat ("<tr>");
      sb.AppendFormat ("<th class='title'>{0}</th>", "#");
      sb.AppendFormat ("<th class='title'>{0}</th>", "At Difficulty");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Name");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Power");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Picture");
      sb.AppendFormat ("<th class='title'>{0}</th>", "HP");
      sb.AppendFormat ("<th class='title'>{0}</th>", "AC");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Nb");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Damage");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Hit Type");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Attack Effect");
      sb.AppendFormat ("<th class='title'>{0}</th>", "XP");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Attack 1");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Attack 2");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Attack 3");
      sb.AppendFormat ("<th class='title'>{0}</th>", "Attack 4");
      sb.AppendFormat ("</tr>");
      sb.AppendLine ();

      foreach (MonsterType monsterType in _monsterTypes)
        sb.AppendLine (monsterType.DumpHtml ().ToString ());

      sb.AppendLineFormat ("</table>");
      return (sb);
    }

    public int CalcFromSize (int size) {
      if (size > 7)
        throw new Exception ();
      return (_sizes [size]);
    }
  }
}
